/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: fzykd
 * Date: 2022-09-28
 * Time: 16:48
 */

//自己先实现一个循环队列 最后加锁一些操作 变为线程安全的阻塞队列
class MyBocKingQueue {
    private int[] data = new int[1000];
    private int size = 0;
    private int head = 0;
    private int tail = 0;

    //这是一个专门的锁对象
    //synchronized 加锁 保证了线程安全 put和take都是操作的公告变量 那么直接加锁即可
    //可以直接加在代码块里 locker指定  this指定
    //或者 直接加在方法前面
    private Object locker = new Object();

    //有了线程安全之后 实现阻塞效果 wait notify
    //明白产生阻塞效果的条件
    //如果队列为空 尝试出队列 就会阻塞 直到不为空
    //如果队列为满 尝试入队列 就会阻塞 知道不为满


    //入队列
    public void put(int value) throws InterruptedException {
        synchronized (locker){ //没有new锁对象的时候 写this指代当前对象
            if (size == data.length){
                //满
                //return;
                locker.wait();
                //put的wait要有take唤醒 只要tack成功一个元素 那么队列就不满了

            }
            //新的元素放入到tail位置上
            data[tail] = value;
            tail++;
            //当tail走到数组的末尾
            if (tail >= data.length){
                tail = 0;
            }
            size++;
            locker.notify();
        }
    }

    //初队列
     public Integer take() throws InterruptedException {
      synchronized (locker){
          if (size == 0){
              //return null;
              //同理
              locker.wait();
          }
          //去除head元素
          int ret = data[head];
          head++;
          if (head >= data.length){
              head = 0;
          }
          size--;
          //这里是take成功之后,唤醒put中的等待
          locker.notify();
          return ret;
      }
    }
}


//阻塞队列
public class Demo3 {
    //简单验证循环队列是否正确
    //验证完之后 加上阻塞条件和线程安全

    //实现一个生产者 消费者模型
    private static MyBocKingQueue queue = new MyBocKingQueue();
    public static void main(String[] args) {
        Thread  producer = new Thread(()->{
            int num = 0;
            while (true){
                System.out.println("生产了: " + num);
                try {
                    queue.put(num);
                    num++;
                    //Thread.sleep(500);
                    //当生产者慢的时候 消费者就只能跟着生产者的步伐
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        producer.start();

        Thread customer = new Thread(()->{
            while (true){
                try {
                    int num = queue.take();
                    System.out.println("消费了: " + num);
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        customer.start();
    }

    public static void main1(String[] args) throws InterruptedException {
        MyBocKingQueue queue = new MyBocKingQueue();
        //先进先出
        queue.put(1);
        queue.put(2);
        queue.put(3);
        queue.put(4);
        int ret = 0;
        ret = queue.take();
        System.out.println(ret);
        ret = queue.take();
        System.out.println(ret);
        ret = queue.take();
        System.out.println(ret);
        ret = queue.take();
        System.out.println(ret);

    }


}
